#! /usr/bin/python
# -*- coding: utf-8 -*-
#
# Universidad Simón Bolívar
# Ingeniería de la Computación
# Traductores e Interpretadores (CI-3725)
# Septiembre - Diciembre 2011
#
# Proyecto 2: Lexer y Parser
#
# Autores:
# César Hernández  (06-39724)  <cesrafa@gmail.com>
# Daniel Valera    (07-41725)  <danielvaleradp@gmail.com>

#LEXER

import ply.lex as lex
import sys
import re
# Lista de Tokens  
tokens = ('STRING', 'INT', 'LIST', 'OF', 'TABLE', \
'IF', 'THEN', 'ELSE', 'TRUE', 'FALSE', 'FBY', \
'TBY', 'INPUT', 'RANGE', 'LEN', \
'PLUS','MINUS','MULT','DIV','MOD', 'POWER', \
'LPAREN','RPAREN','LBRACKET','RBRACKET','LMARK', \
'RMARK','LLISTMARK','RLISTMARK','COLON','COMMA','AND', \
'OR','NEG','EQUAL','NOTEQUAL','GREATER','LESS', \
'GREATEREQUAL','LESSEQUAL','NUMBER','VAR', \
'TEXT','NEW','WHERE')

# Palabras reservadas
reserved = {
    'string' : 'STRING',
    'int' : 'INT',
    'list' : 'LIST',
    'of' : 'OF',
    'table' : 'TABLE',
    'if' : 'IF',
    'then' : 'THEN',
    'else' : 'ELSE',
    'true' : 'TRUE',
    'false' : 'FALSE',
    'fby' : 'FBY',
    'tby' : 'TBY',
    'input' : 'INPUT',
    'range' : 'RANGE',
    'len' : 'LEN',
    'new' : 'NEW',
    'where' : 'WHERE'
}

# Expresiones regulares

#Operadores básicos
t_PLUS = r'\+'
t_MINUS = r'-'
t_MULT = r'\*'
t_DIV = r'/'
t_MOD = r'%'
t_POWER = r'\*\*'

#Delimitadores
t_LPAREN = r'\('
t_RPAREN = r'\)'
t_LBRACKET = r'\['
t_RBRACKET = r'\]'
t_LLISTMARK = r'\[%'
t_RLISTMARK = r'\%]'
t_LMARK = r'\{%'
t_RMARK = r'%\}'
t_COLON = r':'
t_COMMA = r','

#Operadores de condición
t_AND = r'&'
t_OR = r'\|'
t_NEG = r'!'
t_EQUAL = r'='
t_NOTEQUAL = r'!='
t_GREATER = r'\>'
t_LESS = r'\<'
t_GREATEREQUAL = r'\>='
t_LESSEQUAL = r'\<='

def t_NUMBER(t):
    r'\d+'
    try:
        t.value = int(t.value)    
    except ValueError:
        print "Line %d: Number %s is too large!" % (t.lineno,t.value)
        t.value = 0
    return t

def t_VAR(t):
    r'[a-zA-Z]\w*'
    t.type = reserved.get(t.value,'VAR')
    return t

def t_TEXT(t):
    r'\"(\\\"|[^"])*\"'
    t.value = t.value
    return t

def t_newline(t):
    r'\n+'
    t.lexer.lineno += len(t.value)

t_ignore  = ' \t'

def t_error(t):
    print "Caracter no permitido '%s'" % t.value[0]
    t.lexer.skip(1)

lex.lex()

# PARSER
import ply.yacc as yacc

DEBUG = True

precedence = (
    ('left', 'FBY', 'TBY'),
    ('left', 'PLUS', 'MINUS'),
    ('left', 'MULT', 'DIV','POWER'),
    ('right', 'UMINUS')
)

def p_mark(p):
    'mark : LMARK mark_body RMARK'
    
def p_mark_body(p):
    'mark_body : mark_type definition'

def p_mark_type(p):
    'mark_type : EQUAL'
def p_mark_type_empty(p):
    'mark_type : empty'
    
def p_definition(p):
    'definition : many_def'
def p_definition_exp(p):
    'definition : expression'
    
def p_many_def_basecase(p):
    'many_def : VAR COLON type COLON EQUAL expression'
def p_many_def_inductive(p):
    'many_def : VAR COLON type COMMA many_def COMMA expression'  

def p_expression(p):
    'expression : string'
def p_expression_num(p):
    'expression : numeric'
def p_expression_list(p):
    'expression : list'
def p_expression_table(p):
    'expression : table'
def p_expression_arit(p):
    'expression : arit' 
def p_expression_concat(p):
    'expression : concat' 
def p_expression_listaccess(p):
    'expression : list_access'
def p_expression_quantifier(p):
    'expression : quantifier' 
def p_expression_selection(p):
    'expression : selection' 
def p_expression_fby(p):
    'expression : followby' 
def p_expression_tby(p):
    'expression : triggeredby'
def p_expression_len(p):
    'expression : len' 
def p_expression_range(p):
    'expression : range'
def p_expression_input(p):
    'expression : input'
def p_expression_paren(p):
    'expression : LPAREN expression RPAREN'

def p_type(p):
    'type : STRING'
def p_type_int(p):
    'type : INT'
def p_type_liststr(p):
    'type : LIST OF STRING'
def p_type_listint(p):
    'type : LIST OF INT'
def p_type_table(p):
    'type : TABLE'

def p_integer(p):
    'integer : NUMBER'
def p_integer_minus(p):
    'integer : MINUS NUMBER %prec UMINUS'

def p_string(p):
    'string : TEXT'

def p_variable(p):
    'variable : VAR'

def p_numeric(p):
    'numeric : integer'
def p_numeric_variable(p):
    'numeric : variable'

def p_list(p):
    'list : list_types'

def p_list_types(p):
    'list_types : normal_list'
def p_list_types_comprehension(p):
    'list_types : comprehension_list'
    
def p_normal_list(p):
    'normal_list : normal_list COMMA expression'
def p_normal_list_basecase(p):
    'normal_list : expression'

def p_comprehension_list(p):
    'comprehension_list : LLISTMARK VAR COLON list COLON expression RLISTMARK'

def p_table(p):
    'table : NEW TABLE LBRACKET integer RBRACKET WHERE tab_elems'

def p_tab_elems_basecase(p):
    'tab_elems : VAR COLON expression COLON EQUAL expression'
def p_tab_elems_inductive(p):
    'tab_elems : tab_elems COMMA VAR COLON expression COLON EQUAL expression'

def p_operator_arit(p):
    'operator : arit_operator'
def p_operator_bool(p):
    'operator : bool_operator'

def p_arit(p):
    'arit : numeric arit_operator numeric'
def p_arit_operator_plus(p):
    'arit_operator : PLUS' 
def p_arit_operator_minus(p):
    'arit_operator : MINUS'
def p_arit_operator_mult(p):
    'arit_operator : MULT' 
def p_arit_operator_div(p):
    'arit_operator : DIV'
def p_arit_operator_power(p):
    'arit_operator : POWER' 
def p_arit_operator_mod(p):
    'arit_operator : MOD'

def p_concat_str_str(p):
    'concat : string PLUS string'
def p_concat_list_list(p):
    'concat : list PLUS list'
def p_concat_list_str(p):
    'concat : list PLUS string'
def p_concat_str_list(p):
    'concat : string PLUS list'
def p_concat_str_num(p):
    'concat : string PLUS numeric'
def p_concat_num_str(p):
    'concat : numeric PLUS string'

def p_list_access(p):
    'list_access : VAR LBRACKET expression RBRACKET'

def p_quantifier(p):
    'quantifier : LLISTMARK operator VAR COLON list COLON expression RLISTMARK'

def p_selection(p):
    'selection : IF condition THEN expression ELSE expression'

def p_condition_inductive(p):
    'condition : condition bool_operator boolean'
def p_condition_basecase(p):
    'condition : boolean'
    
def p_comparison_equal(p):
    'comparison : EQUAL'
def p_comparison_notequal(p):
    'comparison : NOTEQUAL'
def p_comparison_greater(p):
    'comparison : GREATER'
def p_comparison_less(p):
    'comparison : LESS'
def p_comparison_greaterequal(p):
    'comparison : GREATEREQUAL'
def p_comparison_lessequal(p):
    'comparison : LESSEQUAL'
    
def p_boolean_true(p):
    'boolean : TRUE'
def p_boolean_false(p):            
    'boolean : FALSE'
def p_boolean_inductive(p):            
    'boolean : numeric comparison numeric'
            
def p_bool_operator_and(p):
    'bool_operator : AND'
def p_bool_operator_or(p):
    'bool_operator : OR'
def p_bool_operator_neg(p):
    'bool_operator : NEG'
    
def p_followby(p):
    'followby : expression FBY expression'

def p_triggeredby(p):
    'triggeredby : expression TBY expression'

def p_len(p):
    'len : LEN LPAREN expression RPAREN'

def p_input(p):
    'input : INPUT'

def p_range(p):
    'range : RANGE LPAREN expression COMMA expression RPAREN'

def p_empty(p):
    'empty :'
    pass
    
def p_error(p):
    print "Syntax error!! ",p


# Representación del documento html

html = []
shinyel = []
file = open(sys.argv[1],'r')
expression = r'({%.*?%})'
expression2 = r'{%.*?%}'
compiled = re.compile(expression)
compiled2 = re.compile(expression2)

for line in file:
    temp = compiled.split(line)
    temp2 = compiled2.split(line)
    
    tokens_list = [val for val in temp if val not in temp2]

    html += temp2
    shinyel += tokens_list
    for tok in tokens_list:
        lex.input(tok)
        #while 1:
            #tok = lex.token()
            #if not tok: break
            #print tok
            
print shinyel
yacc.yacc()
yacc.parse(lexer=lex)